<!DOCTYPE html>
<html  lang="zh">
<head>
    <meta charset="utf-8" />

<meta name="generator" content="Hexo 3.8.0" />

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />

<title>【iOS 开发】RunLoop 总结 - OBJC.VIP</title>


    <meta name="description" content="Runloops是线程相关底层基础的一部分。它的本质和字面意思一样运行着的循环（事件处理的循环）。">
<meta name="keywords" content="iOS 开发">
<meta property="og:type" content="article">
<meta property="og:title" content="【iOS 开发】RunLoop 总结">
<meta property="og:url" content="https://objcvip.github.io/RunloopSummary/index.html">
<meta property="og:site_name" content="OBJC.VIP">
<meta property="og:description" content="Runloops是线程相关底层基础的一部分。它的本质和字面意思一样运行着的循环（事件处理的循环）。">
<meta property="og:locale" content="zh-CN">
<meta property="og:image" content="https://objcvip.github.io/images/og_image.png">
<meta property="og:updated_time" content="2019-08-26T10:19:41.000Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="【iOS 开发】RunLoop 总结">
<meta name="twitter:description" content="Runloops是线程相关底层基础的一部分。它的本质和字面意思一样运行着的循环（事件处理的循环）。">
<meta name="twitter:image" content="https://objcvip.github.io/images/og_image.png">







<link rel="icon" href="/images/favicon.svg">


<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.7.2/css/bulma.css">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.4.1/css/all.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Ubuntu:400,600|Source+Code+Pro">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/highlight.js@9.12.0/styles/atom-one-dark.css">


    
    
    
    <style>body>.footer,body>.navbar,body>.section{opacity:0}</style>
    

    
    
    
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/lightgallery@1.6.8/dist/css/lightgallery.min.css">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/justifiedGallery@3.7.0/dist/css/justifiedGallery.min.css">
    

    
    

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/outdatedbrowser@1.1.5/outdatedbrowser/outdatedbrowser.min.css">


    
    
    
    

<link rel="stylesheet" href="/css/back-to-top.css">


    
    

    
    
    
    

    
    
<link rel="stylesheet" href="/css/progressbar.css">
<script src="https://cdn.jsdelivr.net/npm/pace-js@1.0.2/pace.min.js"></script>

    
    
    


<link rel="stylesheet" href="/css/style.css">
</head>
<body class="is-1-column">
    <nav class="navbar navbar-main">
    <div class="container">
        <div class="navbar-brand is-flex-center">
            <a class="navbar-item navbar-logo" href="/">
            
                <img src="/images/logo.svg" alt="【iOS 开发】RunLoop 总结" height="28">
            
            </a>
        </div>
        <div class="navbar-menu">
            
            <div class="navbar-start">
                
                <a class="navbar-item"
                href="/">首页</a>
                
                <a class="navbar-item"
                href="/archives">归档</a>
                
                <a class="navbar-item"
                href="/categories">分类</a>
                
                <a class="navbar-item"
                href="/tags">标签</a>
                
                <a class="navbar-item"
                href="/links">友链</a>
                
                <a class="navbar-item"
                href="/about">关于</a>
                
            </div>
            
            <div class="navbar-end">
                
                
                
                <a class="navbar-item search" title="搜索" href="javascript:;">
                    <i class="fas fa-search"></i>
                </a>
                
            </div>
        </div>
    </div>
</nav>
    
    <section class="section">
        <div class="container">
            <div class="columns">
                <div class="column is-12 has-order-2 column-main"><div class="card">
    
    <div class="card-content article ">
        
        <div class="level article-meta is-size-7 is-uppercase is-mobile is-overflow-x-auto">
            <div class="level-left">
                <time class="level-item has-text-grey" datetime="2017-04-25T16:00:00.000Z">2017-04-26</time>
                
                <div class="level-item">
                <a class="has-link-grey -link" href="/categories/iOS-开发/">iOS 开发</a>
                </div>
                
                
                <span class="level-item has-text-grey">
                    
                    
                    6 分钟 读完 (大约 897 个字)
                </span>
                
                
            </div>
        </div>
        
        <h1 class="title is-size-3 is-size-4-mobile has-text-weight-normal">
            
                【iOS 开发】RunLoop 总结
            
        </h1>
        <div class="content">
            <p>Runloops是线程相关底层基础的一部分。它的本质和字面意思一样运行着的循环（事件处理的循环）。<br><a id="more"></a><br>作用：接受循环事件和安排线程的工作。<br>目的：让线程在有任务的时候忙于工作，而没有任务的时候处于休眠状态。</p>
<h4 id="RunLoop概念"><a href="#RunLoop概念" class="headerlink" title="RunLoop概念"></a>RunLoop概念</h4><p>Runloop运行循环<br>iOS中通常所说的Runloop指的是NSRunloop（Foundation框架）或者CFRunloopRef（CoreFoundation框架），CFRunloopRef是纯C的函数，而NSRunloop仅仅是CFRunloopRef的一层OC封装。</p>
<h4 id="RunLoop作用"><a href="#RunLoop作用" class="headerlink" title="RunLoop作用"></a>RunLoop作用</h4><ol>
<li>保持程序的持续运行。</li>
<li>处理App中的各种事件。（如：touches触摸事件、NSTimer定时器事件、Selector事件）</li>
<li>节省CPU资源，提高程序性能（有事情就做事情，没事情就休息，资源释放）</li>
<li>负责渲染屏幕上的所有UI。</li>
</ol>
<h4 id="RunLoop开启-amp-退出"><a href="#RunLoop开启-amp-退出" class="headerlink" title="RunLoop开启&amp;退出"></a>RunLoop开启&amp;退出</h4><p>在UIApplicationMain函数内部开启了一个和主线程相关的RunLoop (保证主线程不会被销毁)，导致 UIApplicationMain 不会返回，一直在运行中，也就保证了程序的持续运行。<br>Runloop 的退出条件：<br>App退出；线程关闭；设置最大时间到期。</p>
<h4 id="RunLoop和线程关系"><a href="#RunLoop和线程关系" class="headerlink" title="RunLoop和线程关系"></a>RunLoop和线程关系</h4><ol>
<li>每条线程都有唯一的一个与之对应的Runloop对象。</li>
<li>主线程的RunLoop已经自动创建，子线程的RunLoop需要主动创建。</li>
<li>RunLoop在第一次获取时创建，在线程结束时销毁。</li>
<li>Runloop对象是利用字典来进行存储，Key：线程  Value：线程对应的Runloop。</li>
</ol>
<h5 id="创建子线程对应的RunLoop"><a href="#创建子线程对应的RunLoop" class="headerlink" title="创建子线程对应的RunLoop"></a>创建子线程对应的RunLoop</h5><p>currentRunLoop</p>
<h4 id="RunLoop相关类"><a href="#RunLoop相关类" class="headerlink" title="RunLoop相关类"></a>RunLoop相关类</h4><ul>
<li>CFRunLoopRef: RunLoop本身</li>
<li>CFRunLoopModeRef: 运行模式</li>
<li>CFRunLoopSourceRef: 事件源</li>
<li>CFRunLoopTimerRef: Timer事件</li>
<li>CFRunLoopObserverRef: 观察者（监听者）</li>
</ul>
<ol>
<li><p>一条线程 对应一个 Runloop，Runloop 总是运行在某种特定的CFRunLoopModeRef（运行模式）下。</p>
</li>
<li><p>每个 Runloop 都可以包含若干个 Mode ，每个 Mode 又包含Source源 / Timer事件 / Observer观察者。</p>
</li>
<li><p>在 Runloop 中有多个运行模式，每次调用 RunLoop 的主函数<code>__CFRunloopRun()</code>时，只能指定其中一个 Mode（称 CurrentMode）运行， 如果需要切换 Mode，只能是退出 CurrentMode 切换到指定的 Mode 进入，目的以保证不同 Mode 下的 Source / Timer / Observer 互不影响。</p>
</li>
<li><p>Runloop 有效，mode 里面 至少 要有一个timer(定时器事件) 或者是source(源)。</p>
</li>
</ol>
<h5 id="Mode"><a href="#Mode" class="headerlink" title="Mode"></a>Mode</h5><ul>
<li>kCFRunLoopDefaultMode App的默认Mode，通常主线程是在这个Mode下运行。</li>
<li>UITrackingRunLoopMode 界面跟踪 Mode，用于 ScrollView 追踪触摸滑动</li>
<li>UIInitializationRunLoopMode  在刚启动 App 时第进入的第一个 Mode，启动完成后就不再使用。</li>
<li>GSEventReceiveRunLoopMode 接受系统事件的内部 Mode，通常用不到。</li>
<li>kCFRunLoopCommonModes 一种模式组合</li>
</ul>
<h5 id="Source"><a href="#Source" class="headerlink" title="Source"></a>Source</h5><ul>
<li>Source0:非基于端口Port的事件（用于用户主动触发的事件，如：点击按钮或点击屏幕）。</li>
<li>Source：基于端口Port的事件（通过内核和其他线程互相发送消息）</li>
</ul>
<h5 id="Timer"><a href="#Timer" class="headerlink" title="Timer"></a>Timer</h5><p>NSTimer受RunLoop的Mode影响。GCD定时器不受RunLoop影响。</p>
<h5 id="Observer"><a href="#Observer" class="headerlink" title="Observer"></a>Observer</h5><p>消息循环中的监听器</p>
<h4 id="RunLoop休眠"><a href="#RunLoop休眠" class="headerlink" title="RunLoop休眠"></a>RunLoop休眠</h4><p>RunLoop 最核心的事情就是保证线程在没有消息时休眠以避免占用系统资源，有消息时能够及时唤醒。 RunLoop 的这个机制完全依靠系统内核来完成，具体来说是苹果操作系统核心组件 Darwin 中的 Mach 来完成的。</p>

        </div>
        
        <div class="level is-size-7 is-uppercase">
            <div class="level-start">
                <div class="level-item">
                    <span class="is-size-6 has-text-grey has-mr-7">#</span>
                    <a class="has-link-grey -link" href="/tags/iOS-开发/">iOS 开发</a>
                </div>
            </div>
        </div>
        
        
        
    </div>
</div>





<div class="card card-transparent">
    <div class="level post-navigation is-flex-wrap is-mobile">
        
        <div class="level-start">
            <a class="level level-item has-link-grey  article-nav-prev" href="/EffectiveObjectiveCPart1/">
                <i class="level-item fas fa-chevron-left"></i>
                <span class="level-item">Effective Objective-C 2.0（第1章）</span>
            </a>
        </div>
        
        
        <div class="level-end">
            <a class="level level-item has-link-grey  article-nav-next" href="/RuntimeSummary/">
                <span class="level-item">【iOS 开发】Runtime 总结</span>
                <i class="level-item fas fa-chevron-right"></i>
            </a>
        </div>
        
    </div>
</div>



<div class="card">
    <div class="card-content">
        <h3 class="title is-5 has-text-weight-normal">评论</h3>
        
<div id="comment-container"></div>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/gitalk@1.6.0/dist/gitalk.css">
<script src="https://cdn.jsdelivr.net/npm/gitalk@1.6.0/dist/gitalk.min.js"></script>

<script>
    var gitalk = new Gitalk({
        clientID: '7cf9ae5a9ae4228f59ef',
        clientSecret: 'a60824892847d86dab15dae00b18a8227f9af769',
        id: '6921edf8e2fc33a2b4fc34f94afc6da9',
        repo: 'Comments',
        owner: 'objcvip',
        admin: "objcvip",
        createIssueManually: false,
        distractionFreeMode: true
    })
    gitalk.render('comment-container')
</script>

    </div>
</div>
</div>
                
                
            </div>
        </div>
    </section>
    <footer class="footer">
    <div class="container">
        <div class="level">
            <div class="level-start has-text-centered-mobile">
                <a class="footer-logo is-block has-mb-6" href="/">
                
                    <img src="/images/logo.svg" alt="【iOS 开发】RunLoop 总结" height="28">
                
                </a>
                <p class="is-size-7">
                &copy; 2020 ObjC.vip&nbsp;
                All rights reserved.
                
                </p>
            </div>
            <div class="level-end">
            
            </div>
        </div>
    </div>
</footer>
    <script src="https://cdn.jsdelivr.net/npm/jquery@3.3.1/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/moment@2.22.2/min/moment-with-locales.min.js"></script>
<script>moment.locale("zh-CN");</script>

<script>
var IcarusThemeSettings = {
    article: {
        highlight: {
            clipboard: true,
            fold: 'unfolded'
        }
    }
};
</script>


    <script src="https://cdn.jsdelivr.net/npm/clipboard@2.0.4/dist/clipboard.min.js" defer></script>



    
    
    
    <script src="/js/animation.js"></script>
    

    
    
    
    <script src="https://cdn.jsdelivr.net/npm/lightgallery@1.6.8/dist/js/lightgallery.min.js" defer></script>
    <script src="https://cdn.jsdelivr.net/npm/justifiedGallery@3.7.0/dist/js/jquery.justifiedGallery.min.js" defer></script>
    <script src="/js/gallery.js" defer></script>
    

    
    

<div id="outdated">
    <h6>Your browser is out-of-date!</h6>
    <p>Update your browser to view this website correctly. <a id="btnUpdateBrowser" href="http://outdatedbrowser.com/">Update
            my browser now </a></p>
    <p class="last"><a href="#" id="btnCloseUpdateBrowser" title="Close">&times;</a></p>
</div>
<script src="https://cdn.jsdelivr.net/npm/outdatedbrowser@1.1.5/outdatedbrowser/outdatedbrowser.min.js" defer></script>
<script>
    document.addEventListener("DOMContentLoaded", function () {
        outdatedBrowser({
            bgColor: '#f25648',
            color: '#ffffff',
            lowerThan: 'flex'
        });
    });
</script>


    
    
<script src="https://cdn.jsdelivr.net/npm/mathjax@2.7.5/unpacked/MathJax.js?config=TeX-MML-AM_CHTML" defer></script>
<script>
document.addEventListener('DOMContentLoaded', function () {
    MathJax.Hub.Config({
        'HTML-CSS': {
            matchFontHeight: false
        },
        SVG: {
            matchFontHeight: false
        },
        CommonHTML: {
            matchFontHeight: false
        },
        tex2jax: {
            inlineMath: [
                ['$','$'],
                ['\\(','\\)']
            ]
        }
    });
});
</script>

    
    

<a id="back-to-top" title="回到顶端" href="javascript:;">
    <i class="fas fa-chevron-up"></i>
</a>
<script src="/js/back-to-top.js" defer></script>


    
    

    
    
    
    

    
    
    
    
    


<script src="/js/main.js" defer></script>

    
    <div class="searchbox ins-search">
    <div class="searchbox-container ins-search-container">
        <div class="searchbox-input-wrapper">
            <input type="text" class="searchbox-input ins-search-input" placeholder="想要查找什么..." />
            <span class="searchbox-close ins-close ins-selectable"><i class="fa fa-times-circle"></i></span>
        </div>
        <div class="searchbox-result-wrapper ins-section-wrapper">
            <div class="ins-section-container"></div>
        </div>
    </div>
</div>
<script>
    (function (window) {
        var INSIGHT_CONFIG = {
            TRANSLATION: {
                POSTS: '文章',
                PAGES: '页面',
                CATEGORIES: '分类',
                TAGS: '标签',
                UNTITLED: '(无标题)',
            },
            CONTENT_URL: '/content.json',
        };
        window.INSIGHT_CONFIG = INSIGHT_CONFIG;
    })(window);
</script>
<script src="/js/insight.js" defer></script>
<link rel="stylesheet" href="/css/search.css">
<link rel="stylesheet" href="/css/insight.css">
    
</body>
</html>